﻿using System;
using System.Collections.Generic;
using SLNGP.Core.GeneticPrograms;
using SLNGP.Core.Individuals;
using System.Linq;

namespace SLNGP.Core.StopRun
{
    /// <summary>
    /// Stops the current run if any of the conditions has been met.
    /// </summary>
    public class StopRunConditions : IStopRunConditions
    {
        public StopRunConditionsOpearator StopRunConditionsOpearator { get; set; }

        public bool CanStop()
        {
            List<bool?> stopConditions = new List<bool?>()
            {
                ShouldStopBecauseOfIndividualStopCondition(),
                ShouldStopBecauseOfGenerationStopCondition(),
                ShouldStopBecauseOfComplexStopCondition(),
                ShouldStopBecauseOfMaxGenerationsCount()
            };

            if (StopRunConditionsOpearator == StopRunConditionsOpearator.All)
                return stopConditions.All(b => (!b.HasValue) || (b.HasValue && b.Value));
            else if (StopRunConditionsOpearator == StopRunConditionsOpearator.Any)
                return stopConditions.Any(b => b.HasValue && b.Value);
            throw new GeneticProgrammingException(StopRunConditionsOpearator + " is not a valid StopRunConditionsOpearator.");
        }

        public Func<IStopRunConditions, bool> ComplexStopCondition { get; set; }
        public virtual bool? ShouldStopBecauseOfComplexStopCondition()
        {
            if (ComplexStopCondition != null)
                return ComplexStopCondition(this);
            return null;
        }


        public Func<IIndividual, bool> IndividualStopCondition { get; set; }
        public virtual bool? ShouldStopBecauseOfIndividualStopCondition()
        {
            if (IndividualStopCondition != null)
            {
                return Parent.LastRunResults.CurrentGeneration.Any(individual => IndividualStopCondition(individual));
            }
            return null;
        }

        public Func<IGeneration, bool> GenerationStopCondition { get; set; }
        public virtual bool? ShouldStopBecauseOfGenerationStopCondition()
        {
            if (GenerationStopCondition != null)
            {
                return GenerationStopCondition(Parent.LastRunResults.CurrentGeneration);
            }
            return null;
        }

        public int? MaxGenerationsCount { get; set; }
        public virtual bool? ShouldStopBecauseOfMaxGenerationsCount()
        {
            if (MaxGenerationsCount.HasValue)
                return (Parent.LastRunResults.Generations.Count == MaxGenerationsCount.Value);
            return null;
        }

        public IGeneticProgram Parent { get; set; }
    }
}